<template>
  <MapCluster
    ref="cluster"
    v-bind="clusterProps"
    :data="markerData"
    :styleCreator="styleCreator"
    :cursor="cursor"
    v-on="$listeners"
    @ready="activePopup(activeIndex)">
    <!--    <MapPopup-->
    <!--      v-if="!multiple && $scopedSlots.default"-->
    <!--      v-show="marker"-->
    <!--      v-bind="popupProps"-->
    <!--      @hide="handleHide">-->
    <!--      <template v-if="$scopedSlots.title" slot="title">-->
    <!--        <slot v-if="marker" name="title" :marker="marker"></slot>-->
    <!--      </template>-->
    <!--      <slot v-if="marker" :marker="marker"></slot>-->
    <!--    </MapPopup>-->

    <a-Drawer width="400px" :mask="false" v-if="!multiple && $scopedSlots.default" :visible="!!marker" @close="onclose">
      <template v-if="$scopedSlots.title" slot="title">
        <slot v-if="marker" name="title" :marker="marker"></slot>
      </template>
      <slot v-if="marker" :marker="marker"></slot>
    </a-Drawer>

    <template v-if="multiple && $scopedSlots.default">
      <MapPopup
        v-for="(markerItem, index) in markers"
        :key="index"
        v-bind="multiplePopupProps"
        :position="markerItem.coordinate"
        @hide="handleHide(index)">
        <template v-if="$scopedSlots.title" slot="title">
          <slot v-if="markerItem" name="title" :marker="markerItem"></slot>
        </template>
        <slot v-if="markerItem" :marker="markerItem"></slot>
      </MapPopup>
    </template>
  </MapCluster>
</template>

<script>
/**
 * 标记组件
 *
 */
import MapCluster from '../cluster'
import MapPopup from '../popup'
import imageMixin from '../mixins/image'
import parseStyle from '../libs/utils/style'
import { mergeProps } from '../libs/utils/utils'
import defaultMarkerSrc from '@/assets/icon/red.png'

// 浮层默认参数
const defaultPopupProps = {
  title: '信息',
  width: '400px',
  offset: [0, -20],
  autoPan: true
}

/**
 * 插槽
 * @member slots
 * @property {string} default 作用域插槽，定义浮层内容，参数：marker 标记的数据
 * @property {string} title 作用域插槽，定义浮层的标题，参数：marker 标记的数据
 */

export default {
  name: 'MapMarker',
  inject: ['myMap'],
  mixins: [imageMixin],
  components: {
    MapCluster,
    MapPopup
  },
  /**
   * 属性参数
   * @member props
   * @property {number[]} [coordinate] 单个标记时的坐标，无设置data时有效
   * @property {string} [src] 标记的默认图片url，data各项属性无src时采用该值
   * @property {array} [data] 批量生成 marker 的数据
   * @property {number[]} [data.coordinate] 批量生成marker时每个marker的坐标
   * @property {string} [data.src] 批量生成marker的展示图片
   * @property {object} [keyMap] 数据属性映射
   * @property {object} [popup] 浮窗的配置参数
   * @property {Boolean} [multiple] 支持同时显示多个popup, 只对trigger=click 有效
   * @property {string} [trigger] popup打开方式 'click', 'hover'
   * @property {boolean} [cluster] 开启聚合
   * @property {number} [distance] 集群距离，表示在这个像素距离内的是同一群marker
   * @property {string} clusterSrc 集图标图片
   */
  props: {
    // 单个标记时的坐标，无设置data时有效
    coordinate: {
      type: Array,
      default: null
    },
    // 标记的默认图片url，data各项属性无src时采用该值
    src: {
      type: String,
      default: defaultMarkerSrc
    },
    // 群标记图片url
    clusterSrc: {
      type: String,
      default: undefined
    },

    // 激活第几个浮层级
    activeIndex: {
      type: Number,
      default: undefined
    },

    // 数据，[{coordinate, src}]
    data: {
      type: Array,
      default () {
        return []
      }
    },
    // 数据属性映射
    keyMap: {
      type: Object,
      default () {
        return {
          coordinate: 'coordinate',
          src: 'src'
        }
      }
    },
    // 开启集群
    cluster: {
      type: Boolean,
      default: true
    },
    // 相距少于的像素距离就是一群
    distance: {
      type: Number,
      default: 20
    },
    zIndex: {
      type: Number,
      default: 900
    },
    // 浮窗的配置参数
    popup: {
      type: Object,
      default () {
        return defaultPopupProps
      }
    },
    multiple: Boolean,

    // 浮窗显示触发方式
    trigger: {
      type: String,
      default: 'click',
      validator (val) {
        return ['click', 'hover'].includes(val)
      }
    }
  },
  data () {
    return {
      // 激活时的数据
      marker: null,
      // multiple 为true时，激活的数据
      markers: [],
      heightFeature: null
    }
  },
  computed: {
    markerData () {
      const { coordinate, src } = this.keyMap
      const data = this.data.length > 0
        ? this.data
        : (this.coordinate ? [{ coordinate: this.coordinate }] : [])
      return data.map(item => {
        return {
          ...item,
          coordinate: item[coordinate],
          src: item[src]
        }
      })
    },
    clusterProps () {
      return mergeProps(this, ['keyMap', 'distance', 'cluster', 'zIndex'])
    },
    // MyMapImage配置参数
    imageProps () {
      const keys = Object.keys(imageMixin.props)
      return mergeProps(this, keys)
    },
    // MyMapPopup配置参数
    popupProps () {
      if (!this.marker || this.multiple) return null
      const position = this.marker.coordinate
      return {
        ...defaultPopupProps,
        ...this.popup,
        position
      }
    },
    multiplePopupProps () {
      if (!this.multiple) return null
      return {
        ...defaultPopupProps,
        ...this.popup
      }
    },
    cursor () {
      return this.trigger === 'click'
    }
  },
  watch: {
    activeIndex (val) {
      this.activePopup(val)
    }
  },
  methods: {
    onclose () {
      this.marker = null
      this.$emit('close')
    },
    styleCreator (feature) {
      return this.cluster
        ? this.createClusterStyle(feature)
        : this.createFeatureStyle(feature)
    },
    createFeatureStyle (feature, clusterSrc) {
      const data = feature.get('data')
      const { coordinate, src, style } = data
      if (style) {
        const config = {
          fill: '#409eff',
          radius: 10,
          strokeWidth: 1,
          strokeColor: '#fff',
          textFill: '#fff',
          scaleSeed: 0.0001,
          ...style
        }
        const styleConfig = {
          circle: {
            radius: config.radius + config.scaleSeed * 1,
            stroke: {
              width: config.strokeWidth,
              color: config.strokeColor
            },
            fill: config.fill
          }
        }
        return parseStyle(styleConfig)
      } else {
        const icon = {
          ...this.imageProps,
          coordinate,
          src: clusterSrc || src || this.src
        }
        return parseStyle({ icon })
      }
    },
    createClusterStyle (cluster) {
      const features = cluster.get('features')
      return this.createFeatureStyle(features[0], this.clusterSrc)
    },
    activePopup (index) {
      const cluster = this.$refs.cluster
      if (!cluster) return
      const source = cluster.getSource()
      if (!source) return
      const features = source.getFeatures() || []
      const feature = features[index]
      feature && this.showPopup({}, feature)
    },
    showPopup (e, feature) {
      if (!feature) return
      const coordinate = feature.getGeometry().getCoordinates()
      const features = feature.get('features') || []

      const marker = {
        coordinate,
        cluster: false,
        items: []
      }
      if (features.length > 0) {
        marker.items = features.map(f => f.get('data'))
        marker.cluster = true
      } else {
        marker.items = [feature.get('data')]
      }
      this.heightFeature && this.heightFeature.forEach(item => {
        item.setStyle(null)
      })

      if (this.multiple) {
        this.markers.push(marker)
        this.heightFeature = features
      } else {
        this.marker = marker
        this.heightFeature = [feature]
      }

      this.$emit('show', marker, feature, e)
    },
    handleHide (index = 0) {
      if (this.multiple) {
        const marker = this.markers.splice(index, 1)
        this.$emit('hide', marker)
      } else {
        this.$emit('hide', this.marker)
        this.marker = null
      }
    },
    bindEvents () {
      const cluster = this.$refs.cluster
      switch (this.trigger) {
        case 'click':
          cluster.$on('click', this.showPopup)
          break
        case 'hover':
          cluster.$on('mouseenter', this.showPopup)
          cluster.$on('mouseleave', this.handleHide)
          break
      }
    },
    draw (data = []) {
      const cluster = this.$refs.cluster
      if (cluster) {
        cluster.draw(data)
      }
    },
    clear () {
      const cluster = this.$refs.cluster
      if (cluster) {
        cluster.clear()
      }
    }
  },
  mounted () {
    this.bindEvents()
  },
  beforeDestroy () {
    const cluster = this.$refs.cluster
    if (cluster) {
      cluster.$off()
    }
  }
}
</script>
